package com.ebupt.migu.music.schedule;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.ebupt.migu.music.common.exception.MiguRuntimeException;
import com.ebupt.migu.music.common.util.HttpUtils;
import com.ebupt.migu.music.statistics.entity.PushResult;
import com.ebupt.migu.music.statistics.service.impl.StatisticsPushTaskServiceImpl;
import com.ebupt.migu.music.strategy.entity.StrategyInfo;
import com.ebupt.migu.music.userGroup.entity.UserGroupInfo;

import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

/**
 * @author lizm
 */
@Slf4j
@Component
@EnableScheduling
@RestController
@RequestMapping("/strategyTask")
public class StrategyTask {
    @Autowired
    private StatisticsPushTaskServiceImpl stService;
    @Value("${push.push_result_url}")
    private String PUSH_RESULT_URL;
    @Value("${push.ip}")
    private String PUSH_IP;
    @Value("${push.app_id}")
    private String APP_ID;
    @Value("${push.pushChannel}")
    private String pushChannel;
    @Value("${push.push_result_duration}")
    private String pushResultDuration;
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * push推送后48小时更新 Push效果统计-系统定时向Push服务器发起访问，获取统计结果
     */
    @Scheduled(initialDelay = 1000 * 60, fixedRate = 1000 * 60 * 10)
    public void autoGetPushResult() throws Exception {
        log.info("定时任务push统计开始");
        // 获取已推送的PUSH策略
        List<PushResult> resultList = stService.queryPushResultList();
        if (CollectionUtils.isNotEmpty(resultList)) {
            for (int i = 0, length = resultList.size(); i < length; i++) {
                boolean isCreate = false;
                PushResult pushResult = resultList.get(i);
                String taskId = pushResult.getStrategyId() + pushResult.getPushDate();
                long pushTime = pushResult.getCreateTime().getTime();
                long today = new Date().getTime();
                long distanceTime = today - pushTime;
                long resultDuration = (long)(Float.parseFloat(pushResultDuration) * 60 * 60 * 1000);
                // push推送48小时后去获取统计结果--只调一次
                if (distanceTime > resultDuration) {
                    isCreate = true;
                }
                if (isCreate) {
                    updatePushResultData(pushResult, taskId);
                }
            }
            log.info("定时任务结束：autoGetPushResult");
        } else {
            log.info("没有可调用push统计");
        }
    }

    /**
     * 构造map
     * 
     * @param strategyInfo
     * @param groupInfo
     * @return
     */
    private Map<String, Object> paramsResult(StrategyInfo strategyInfo, UserGroupInfo groupInfo) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("strategyId", strategyInfo.getStrategyId());
        paramMap.put("strategyName", strategyInfo.getStrategyName());
        paramMap.put("strategyCreateTime", strategyInfo.getCreateTime());
        paramMap.put("groupId", strategyInfo.getGroupId());
        paramMap.put("groupName", strategyInfo.getGroupName());
        if (null != groupInfo) {
            paramMap.put("groupSize", groupInfo.getClientUser());
        }
        paramMap.put("lastUpdateTime", new Date());
        paramMap.put("executeType", strategyInfo.getExecuteType());
        paramMap.put("creatorDepartment", strategyInfo.getCreatorDepartment());
        // 新增push统计结果
        paramMap.put("createTime", new Date());
        return paramMap;
    }

    /**
     *
     * @param taskId
     * @return
     * @throws Exception
     */
    @PostMapping("/pushResult")
    public String PushResult(String taskId, String channel) {
        // 设置HTTP接口post参数
        if (StringUtils.isNotBlank(taskId)) {
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("appId", APP_ID);
            paramsMap.put("taskId", taskId);
            paramsMap.put("pushChannel", pushChannel);
            if ("1".equals(channel)) {
                paramsMap.put("appType", "music");
            }
            if ("2".equals(channel)) {
                paramsMap.put("appType", "media");
            }
            Map<String, String> header = new HashMap<>();
            header.put("Content-Type", "application/json");
            header.put("charset", "utf-8");
            // 调用HTTP接口
            String result = "";
            try {
                result = HttpUtils.doPost(PUSH_IP + PUSH_RESULT_URL, paramsMap, header);
            } catch (Exception e) {
                log.error("调用PUSH结果统计接口失败", e);
                throw new MiguRuntimeException("调用PUSH结果统计接口失败", e);
            }
            return result;
        }
        return null;
    }

    /**
     * num1/num2的百分比
     * 
     * @param num1
     * @param num2
     * @return
     */
    private static String getProportion(int num1, int num2) {
        if (num2 == 0) {
            return "0.00%";
        }
        NumberFormat numberFormat = NumberFormat.getInstance();
        numberFormat.setMaximumFractionDigits(2);
        String result = numberFormat.format((float)num1 / (float)num2 * 100);
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        if (pattern.matcher(result).matches()) {
            return result.concat(".00").concat("%");
        }
        return result.concat("%");
    }

    private void updatePushResultData(PushResult pushResult, String taskId) {
        StrategyInfo strategyInfo = stService.queryByStrategyId(pushResult.getStrategyId());
        UserGroupInfo groupInfo = new UserGroupInfo();
        if (null != strategyInfo.getGroupId() && !"".equals(strategyInfo.getGroupId())) {
            groupInfo = stService.queryByGroupId(strategyInfo.getGroupId());
        }
        if (null != strategyInfo) {
            log.info("正在获取taskId：{}push效果数据", taskId);
            String result = PushResult(taskId, strategyInfo.getSendChannel());
            if (result != null) {
                log.info("PUSH结果统计返回:{}", result);
                JSONObject jsonObject = new JSONObject(result);
                String code = jsonObject.getStr("code");
                String msg = jsonObject.getStr("msg");
                // 接口返回成功code
                if (code.equals("000000")) {
                    JSONObject data = jsonObject.getJSONObject("data");
                    Map<String, Object> paramMap = paramsResult(strategyInfo, groupInfo);
                    paramMap.put("taskId", taskId);
                    // 百日联网数--对端用户去重
                    paramMap.put("msgTotal", data.getStr("msgTotal"));
                    // 在线用户数
                    paramMap.put("onlineNum", data.getStr("onlineNum"));
                    JSONObject android = data.getJSONObject("android");
                    // 成功下发-android
                    int androidSend = Integer.parseInt(android.getStr("sent") != null ? android.getStr("sent") : "0");
                    // 展示数-android
                    int androidDisplayed =
                        Integer.parseInt(android.getStr("displayed") != null ? android.getStr("displayed") : "0");
                    // 点击数-android
                    int androidClicked =
                        Integer.parseInt(android.getStr("clicked") != null ? android.getStr("clicked") : "0");
                    JSONObject ios = data.getJSONObject("ios");
                    // 展示数-ios
                    int iosDisplayed =
                        Integer.parseInt(ios.getStr("displayed") != null ? ios.getStr("displayed") : "0");
                    // 点击数-ios
                    int iosClicked = Integer.parseInt(ios.getStr("clicked") != null ? ios.getStr("clicked") : "0");
                    // 成功下发-ios
                    int iosSend = Integer.parseInt(ios.getStr("sent") != null ? ios.getStr("sent") : "0");
                    // 成功下发-总数
                    int totalSend = iosSend + androidSend;
                    // 展示数-总数
                    int totalDisplayed = iosDisplayed + androidDisplayed;
                    // 点击数-总数
                    int totalClicked = iosClicked + androidClicked;
                    log.info(
                        "androidSend:{}, " + "androidDisplayed:{}, " + "androidClicked:{}, " + "iosDisplayed:{}, "
                            + "iosSend:{}, " + "iosClicked:{}, " + "totalSend:{}, " + "totalDisplayed:{}, "
                            + "totalClicked:{}",
                        androidSend, androidDisplayed, androidClicked, iosDisplayed, iosSend, iosClicked, totalSend,
                        totalDisplayed, totalClicked);
                    // 转化率=点击数/成功下发数 --百分数
                    // 转化率采用字符串存储
                    String totalCrv = getProportion(totalClicked, totalDisplayed);
                    String iosCrv = getProportion(iosClicked, iosDisplayed);
                    String androidCrv = getProportion(androidClicked, androidDisplayed);
                    paramMap.put("androidSend", androidSend);
                    paramMap.put("androidDisplayed", androidDisplayed);
                    paramMap.put("androidClicked", androidClicked);
                    paramMap.put("iosDisplayed", iosDisplayed);
                    paramMap.put("iosClicked", iosClicked);
                    paramMap.put("iosSend", iosSend);
                    paramMap.put("totalSend", totalSend);
                    paramMap.put("totalDisplayed", totalDisplayed);
                    paramMap.put("totalClicked", totalClicked);
                    paramMap.put("totalCrv", totalCrv);
                    paramMap.put("iosCrv", iosCrv);
                    paramMap.put("androidCrv", androidCrv);
                    paramMap.put("pushTime", pushResult.getCreateTime());
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                    String s = sdf.format(strategyInfo.getExecuteTime());
                    String key_iop = pushResult.getStrategyId() + "_" + s + "_iop";
                    String key_incr = pushResult.getStrategyId() + "_" + s + "_incr";
                    String key_black = pushResult.getStrategyId() + "_" + s + "_black";
                    int i = redisTemplate.hasKey(key_incr) == null ? 0
                        : Integer.parseInt(null == redisTemplate.opsForValue().get(key_incr) ? "0"
                            : String.valueOf(redisTemplate.opsForValue().get(key_incr)));
                    int iopUser =
                        redisTemplate.hasKey(key_iop) == null ? 0 : (redisTemplate.opsForValue().get(key_iop) == null
                            ? 0 : Integer.valueOf(String.valueOf(redisTemplate.opsForValue().get(key_iop))));
                    paramMap.put("intersectionUser", iopUser);
                    paramMap.put("blackUser",
                        redisTemplate.hasKey(key_black) == null ? 0
                            : (redisTemplate.opsForValue().get(key_black) == null ? 0
                                : redisTemplate.opsForValue().get(key_black)));
                    paramMap.put("bdUser", groupInfo.getClientUser());
                    if (null == groupInfo || null == groupInfo.getClientUser()) {
                        paramMap.put("totalFailure", 0);
                    } else {
                        paramMap.put("totalFailure",
                            groupInfo.getClientUser() - i < 0 ? 0 : groupInfo.getClientUser() - i);
                    }
                    paramMap.put("repetitionUser", null);
                    paramMap.put("errSend", null);
                    paramMap.put("failSend", null);
                    paramMap.put("iopUser", null);
                    // 如果存在taskId 调用修改方法
                    int j = stService.IsHaveTaskId(taskId) == true ? stService.updateStatisPush(paramMap)
                        : stService.createStatisPush(paramMap);
                    log.info("调用获取PUSH效果统计接口groupresult.do==成功， create StatisticsPush:" + j);
                    if (j > 0) {
                        stService.updatePushResultStatus(pushResult.getStrategyId(), pushResult.getPushDate());
                    }
                } else {
                    log.info("调用获取PUSH效果统计接口groupresult.do失败");
                    throw new MiguRuntimeException("调用获取PUSH效果统计接口groupresult.do失败" + msg);
                }
            }
        }
    }

    /**
     * 启动某一天的push效果数据统计
     */
    @PostMapping("/synchronizePushResult")
    public void synchronizePushResult(@RequestParam("pushDate") String pushDate) {
        // 获取已推送的PUSH策略
        log.info(">>>>>>>>>>>>>>>>pushDate:{}", pushDate);
        List<PushResult> resultList = stService.queryPushResultList(pushDate);
        log.info(">>>>>>>>>>>>>>>>查询出当天的push策略共{}条", resultList.size());
        if (resultList.size() <= 0) {
            return;
        }
        int num = 0;
        for (PushResult pushResult : resultList) {
            String taskId = pushResult.getStrategyId() + pushResult.getPushDate();
            updatePushResultData(pushResult, taskId);
            log.info(">>>>>>>>>>>>>>>>>第{}个{}更新完成", ++num, taskId);
        }
    }

}